package com.toycloud.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.amazonaws.services.s3.model.CompleteMultipartUploadResult;
import com.amazonaws.services.s3.model.PartSummary;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.toycloud.business.service.ISysUploadTaskService;
import com.toycloud.common.core.utils.StringUtils;
import com.toycloud.common.exception.ServiceException;

import com.toycloud.oss.core.OssClient;
import com.toycloud.oss.enumd.AccessPolicyType;
import com.toycloud.oss.factory.OssFactory;



import com.toycloud.system.domain.SysOss;
import com.toycloud.system.domain.SysUploadTask;
import com.toycloud.system.domain.bo.InitTaskParam;
import com.toycloud.system.domain.dto.TaskInfoDTO;
import com.toycloud.system.domain.dto.TaskRecordDTO;
import com.toycloud.system.domain.vo.SysOssVo;
import com.toycloud.system.mapper.SysOssMapper;
import com.toycloud.system.mapper.SysUploadTaskMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 文件分片上传任务 服务层实现
 *
 * @author rrge
 */
@RequiredArgsConstructor
@Service
public class SysUploadTaskServiceImpl implements ISysUploadTaskService {

    private final SysUploadTaskMapper uploadTaskMapper;

    private final SysOssMapper sysOssMapper;

    @Override
    public SysUploadTask getByIdentifier(String identifier) {
        return uploadTaskMapper.selectOne(new LambdaQueryWrapper<SysUploadTask>().eq(SysUploadTask::getFileIdentifier, identifier));
    }

    @Override
    public TaskInfoDTO initTask(InitTaskParam param) {
        OssClient storage = OssFactory.instance();
        String fileName = param.getFileName();
        String suffix = StringUtils.substring(fileName, fileName.lastIndexOf("."), fileName.length());
        String key = storage.getPath(storage.getPrefix(), suffix);
        String uploadId = storage.createUploadId(key);

        SysUploadTask task = new SysUploadTask();
        int chunkNum = (int) Math.ceil(param.getTotalSize() * 1.0 / param.getChunkSize());
        task.setChunkNum(chunkNum)
                .setChunkSize(param.getChunkSize())
                .setTotalSize(param.getTotalSize())
                .setFileIdentifier(IdUtil.fastSimpleUUID())
                .setFileName(fileName)
                .setObjectKey(key)
                .setUploadId(uploadId);
        uploadTaskMapper.insert(task);
        return new TaskInfoDTO().setTaskRecord(TaskRecordDTO.convertFromEntity(task));
    }

    @Override
    public String getPath(String objectKey) {
        OssClient storage = OssFactory.instance();
        return StrUtil.format("{}/{}", storage.getUrl(), objectKey);
    }

    @Override
    public String genPreSignUploadUrl(String objectKey, String uploadId, int partNumber) {
        OssClient storage = OssFactory.instance();
        return storage.createPreSignUploadUrl(objectKey, uploadId, partNumber);
    }

    @Override
    public SysOssVo merge(String identifier) {
        SysUploadTask task = getByIdentifier(identifier);
        if (ObjectUtil.isNull(task)) {
            throw new ServiceException("分片任务不存在！");
        }
        OssClient storage = OssFactory.instance();
        List<PartSummary> parts = storage.listParts(task.getObjectKey(), task.getUploadId());
        if (!task.getChunkNum().equals(parts.size())) {
            // 已上传分块数量与记录中的数量不对应，不能合并分块
            throw new ServiceException("分片缺失，请重新上传");
        }

        CompleteMultipartUploadResult result = storage.completeMultipartUpload(task.getObjectKey(), task.getUploadId(), parts);

        String suffix = StringUtils.substring(task.getFileName(), task.getFileName().lastIndexOf("."), task.getFileName().length());
        SysOss oss = new SysOss();
        oss.setOssId(task.getId());
        oss.setUrl(getPath(task.getObjectKey()));
        oss.setFileSuffix(suffix);
        oss.setFileName(result.getKey());
        oss.setOriginalName(task.getFileName());
        oss.setService(storage.getConfigKey());
        sysOssMapper.insert(oss);

        SysOssVo sysOssVo = BeanUtil.toBean(oss, SysOssVo.class);
        if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) {
            sysOssVo.setUrl(storage.getPrivateUrl(task.getObjectKey(), 120));
        }
        return sysOssVo;
    }
}
